package core;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.NoSuchElementException;
import java.util.Scanner;

import org.jfree.ui.RefineryUtilities;

import mutations.Clasical;
import mutations.Mutation;
import mutations.NoUniformGeneration;
import neural.Function;
import neural.Net;
import neural.Tangh;
import select.Boltzmann;
import select.Elite;
import select.MixBoltzman;
import select.MixRoulette;
import select.Roulette;
import select.Selection;
import select.Universal;
import select.comparators.Maximize;
import test.LineChartDemo2;
import crossover.AnularCrossover;
import crossover.ClassicCrossover;
import crossover.Crossover;
import crossover.MultipointCrossover;
import crossover.ParametrizedUniformCrossover;
import cutCriteria.ContentCutCriteria;
import cutCriteria.CutCriteria;
import cutCriteria.GenerationsCutCriteria;
import cutCriteria.OptimumEnvironmentCutCriteria;
import cutCriteria.StructureCutCriteria;

public class Main {

	/**
	 * @param args
	 */
	private static Double optimum;
	
		public static void main(String[] args) {
			
			String fileName;
			if(args.length == 0){
				fileName = "files/parametros1.txt";
				System.out.println("Utilizando parametros del archivo parametros1.txt en la carpeta files");
			}else{
				fileName = args[0];
				System.out.println("Utilizando archivo " + args[0]);
			}

			Scanner scanner;
			try {
				scanner = new Scanner(new File(fileName));
			} catch (FileNotFoundException e1) {
				System.out.println(fileName + "not found");
				return;
			}
			
			Net red = Net.getInstance();
			Function f = new Tangh(1);
			int[] nodos = {9,8};
			red.initialize(2, nodos, f);
			
			scanner.useDelimiter("\r\n");
			
			String line = getLine(scanner);
			
			int popSize;
			try{
				popSize = Integer.valueOf(line);
			}catch(Exception e){
				System.out.println("Invalid line: 3. Expected population size");
				return;
			}
			Double backpropProbability;
			line = getLine(scanner);
			try{
				backpropProbability = Double.valueOf(line);
			}catch(Exception e){
				System.out.println("Invalid line 5. Expected Backpropagation probability");
				return;
			}
			int maxGeneration;
			line = getLine(scanner);
			try{
				maxGeneration = Integer.valueOf(line);
			}catch(Exception e){
				System.out.println("Invalid line 7.  Expected max generations");
				return;
			}

			Double generationalBreach;
			line = getLine(scanner);
			try{
				generationalBreach = Double.valueOf(line);
			}catch(Exception e){
				System.out.println("Invalid line 9.  Expected max generations");
				return;
			}

			Double mutationProbability;
			line = getLine(scanner);
			try{
				mutationProbability = Double.valueOf(line);
			}catch(Exception e){
				System.out.println("Invalid line 11. Expected mutation probability");
				return;
			}
			
			Mutation mutation = null;
			line = getLine(scanner);
			if(line.trim().toLowerCase().equals("uniforme")){
				mutation = new Clasical(mutationProbability);
			}else if(line.trim().toLowerCase().equals("nouniforme")){
				mutation = new NoUniformGeneration(mutationProbability, 0.001, 10);				
			}else{
				System.out.println("Invalid argument line 13. Expected values for mutation type are Uniforme o NoUniforme");
				return;
			}
			
			Crossover crossover = null;
			line = getLine(scanner);
			if(line.trim().toLowerCase().equals("point")){
				crossover = new ClassicCrossover();
			}else if(line.substring(0, 6).toLowerCase().equals("anular")){
				int points[] = getPoints(line.substring(6));
				if(points == null){
					System.out.println("Invalid line 15. Expected unrepeated numbers in decreasing order seperated by comas and no spaces.");
					return;
				}else{
					crossover = new AnularCrossover(points[0]);
				}
			}else if(line.substring(0,7).toLowerCase().equals("uniform")){
				Double crossOverProbability = null;
				try{
					crossOverProbability = Double.valueOf(line.substring(7));
					crossover = new ParametrizedUniformCrossover(crossOverProbability);
				}catch(Exception e){
					System.out.println("Invalid line 15. Expected probability for segmented crossover");
					return;
				}
			}else if(line.substring(0,11).trim().toLowerCase().equals("multipoint")){
				int points[] = getPoints(line.substring(11));
				if(points == null){
					System.out.println("Invalid line 15. Expected unrepeated numbers in decreasing order seperated by comas and no spaces.");
					return;
				}else{
					crossover = new MultipointCrossover(points);
				}
			}/*else if(args[argc].toLowerCase().equals("segmented")){
				
				Double crossOverProbability = null;
				try{
					crossOverProbability = Double.valueOf(args[++argc]);
				}catch(Exception e){
					System.out.println("Invalid argument " + (argc + 1) + ". Expected probability for segmented crossover");
					return;
				}
				//crossover = new SegmentedCrossover(crossOverProbability);
			}*/else{
				System.out.println("Invalid line 15. Expected crossover methods are: anular, bit, multipoint, segmented");
				return;
			}
			
			line = getLine(scanner);
			Selection selection = getSelection(line, (int) ((1-generationalBreach)*popSize), generationalBreach, popSize);
			if(selection == null){
				System.out.println("Invalid line 17. Expected selection methods are: Elite, Rest, Universal, Roulette, MixUniversal, MixRoulette");
				return;
			}
			
			line = getLine(scanner);
			Selection replacement = getSelection(line, (int) ((1-generationalBreach)*popSize), generationalBreach, popSize);
			if(replacement == null){
				System.out.println("Invalid line 19. Expected selection methods are: Elite, Rest, Universal, Roulette, MixUniversal, MixRoulette");
				return;
			}
			
			CutCriteria criteria;
			line = getLine(scanner);
			if(line.trim().toLowerCase().equals("generations")){
				criteria = new GenerationsCutCriteria();
			}else if(line.substring(0, 7).toLowerCase().equals("content")){
				Double delta;
				try{
					delta = Double.valueOf(line.substring(7).trim());
				}catch(Exception e){
					System.out.println("Invalid line 21. Expected double percentage for content criteria");
					return;
				}
				criteria = new ContentCutCriteria(delta);
			}else if(line.toLowerCase().equals("optimum")){
				criteria = new OptimumEnvironmentCutCriteria(optimum, 2, 3);
			}else if(line.substring(0, 9).toLowerCase().equals("structure")){
				Integer percentage;
				try{
					percentage = Integer.valueOf(line.substring(9).trim());
				}catch(Exception e){
					System.out.println("Invalid line 21. Expected integer percentage for structure criteria");
					return;
				}
				criteria = new StructureCutCriteria(percentage);
			}else{
				System.out.println("Invalid line 21. Expected values are: Content, Generations, Optimum, Structure,");
				return;
			}
			
			Problem problem = new Problem(popSize,maxGeneration,mutationProbability,mutation,selection,replacement,criteria,generationalBreach, backpropProbability);
//			problem.setComparator(comp);
			problem.setComparator(new Maximize());
			problem.setCrossover(crossover);
			problem.solve();
			LineChartDemo2 localLineChartDemo2 = new LineChartDemo2(problem.getStatisticList(),"JFreeChart: LineChartDemo2.java");
			localLineChartDemo2.pack();
			RefineryUtilities.centerFrameOnScreen(localLineChartDemo2);
			localLineChartDemo2.setVisible(true);
		}
		

		private static int[] getPoints(String numbers){
			String[] values = numbers.replaceAll("\\s","").split(",");
			int points[] = new int[values.length];
			Integer previous = null;
			for(int i = 0; i < values.length; ++i){
				try{
					points[i] = Integer.valueOf(values[i]);
				}catch(Exception e){
					return null;
				}
				if(previous != null){
					if(points[i] < previous){
						return null; 
					}
				}
				previous = points[i];
				
			}
			return points;
		}
		
		private static Selection getSelection(String line, int parentSize, Double genBreach, Integer popSize){
			if(line.trim().toLowerCase().equals("elite")){
				return new Elite();
			}else if(line.trim().toLowerCase().equals("universal")){
				return new Universal(parentSize);
			}else if(line.trim().toLowerCase().equals("roulette")){
				return new Roulette();
			}else if(line.trim().toLowerCase().equals("boltzman")){
				return new Boltzmann(4000);
			}else if(line.substring(0, 11).trim().toLowerCase().equals("mixroulette")){
				Integer selected;
				try{
					selected = Integer.valueOf(line.substring(11).trim());
					if(selected >= parentSize){
						System.out.println("Invalid line 17 or 19. Expected amount should be lower than parent size");
						return null;
					}
				}catch(Exception e){
					System.out.println("Invalid line 17 or 19. Expected selection methods are: Elite, Rest, Universal, Roulette, MixUniversal, MixRoulette");
					return null;
				}
				return new MixRoulette((int) ((genBreach/selected)*popSize));
			}else if(line.substring(0, 11).trim().toLowerCase().equals("mixboltzman")){
				Integer selected;
				try{
					selected = Integer.valueOf(line.substring(11).trim());
					if(selected >= parentSize){
						System.out.println("Invalid line 17 or 19. Expected amount should be lower than parent size");
						return null;
					}
				}catch(Exception e){
					System.out.println("Invalid line 17 or 19. Expected selection methods are: Elite, Rest, Universal, Roulette, MixUniversal, MixRoulette");
					return null;
				}
				return new MixBoltzman((int) ((genBreach/selected)*popSize));
			}else{
				System.out.println("Invalid line 17 or 19. Expected selection methods are: Elite, Rest, Universal, Roulette, MixUniversal, MixRoulette");
				return null;
			}
		}
		
		private static String getLine(Scanner scanner){
			String line = scanner.next();
			try{
				while(line.startsWith("#")){
					line = scanner.next();
				}
			}catch(NoSuchElementException e){
				System.out.println("Archivo invalido");
				return null;
			}
			return line;
		}

}
